import { _decorator, Component, ERaycast2DType, ERigidBody2DType,math, Node, PhysicsSystem2D, PolygonCollider2D, RigidBody2D, Sprite, tween, UITransform, Vec2, Vec3 } from 'cc';
import { DIRECTION_ENUM, LEAPING_NAME_ENUM, PARAME_NAME_ENUM } from '../../Enums';
import { createUINode,generateEllipsePoints, getFrameAsset, getRandomNumber,roundToNearestInteger } from '../utils';
import DataManager from '../Runtime/DataManager';
import { NpcPlayManager } from '../Player/NpcPlayManager';
const { ccclass} = _decorator;
@ccclass('BaseEnemy')
export class BaseEnemy extends Component {
    _status: string = ""
    _dizzy: Boolean = false //是否晕倒
    avoid: Boolean = false  //是否躲避
    perpetrator: Node //被哪个道具撞到了
    speed: number
    offline: Boolean = false //是否离线
    playManager: NpcPlayManager
    play_node: Node
    shadow: Node
    positionX: number
    positionY: number
    offsetY: number = 0
    offsetX: number = 0
    userNode: Node
    initialize: Boolean = false
    lineList: Array<{ targetX: number, targetY: number, direction: DIRECTION_ENUM, status: string }> = []
    nodeName: string = ""
    dizzy_direction: string = ""
    static_enum
    callback
    callback_A
    callbackAvoid
    fly: Boolean = false
    get dizzy() {
        return this._dizzy
    }
    set dizzy(value: Boolean) {
        if(this.dizzy!=value){
            this._dizzy = value
            if (value) {
                this.playManager.targetX = 0
                this.playManager.targetY = 0
                clearTimeout(this.callback)
                clearTimeout(this.callback_A)
                this.getEmptyPhysics(this.dizzy_direction)
            }
        }
    }
    get status() {
        return this._status
    }
    set status(value: string) {
        this._status = value
        if (this.playManager.direction == DIRECTION_ENUM.LEFT) {
            this.userNode.setScale(-2.5, 2.5, 1)
            this.userNode.setScale(-2.5, 2.5, 1)
        } else {
            this.userNode.setScale(2.5, 2.5, 1)
            this.userNode.setScale(2.5, 2.5, 1)
        }
        if (this.playManager.direction == DIRECTION_ENUM.BOTTOM || this.playManager.direction == DIRECTION_ENUM.TOP) {
            this.userNode.setPosition(this.positionX, this.positionY)
        } else {
            this.userNode.setPosition(this.offsetX, this.offsetY)
        }
    }
    onDestroy() {
        clearTimeout(this.callback)
        clearTimeout(this.callback_A)
    }
    // 怪物初始化
    initialization(
        nodeName: string,
        positionX: number,
        positionY: number,
        offsetX: number,
        offsetY: number,
        static_enum,
        list
    ) {
        this.static_enum = static_enum
        this.offsetX = offsetX
        this.offsetY = offsetY
        this.positionY = positionY
        this.positionX = positionX
        this.nodeName = nodeName
        const node = createUINode(nodeName)
        node.setParent(this.node)
        this.play_node = node
        const rigidBody2D = this.node.addComponent(RigidBody2D)
        rigidBody2D.gravityScale = 0
        rigidBody2D.fixedRotation = true
        rigidBody2D.type = ERigidBody2DType.Dynamic
        rigidBody2D.enabledContactListener = true
        const polygonCollider2D = this.node.addComponent(PolygonCollider2D)
        polygonCollider2D.points = [...generateEllipsePoints(DataManager.Instance.width / 2 - 4, DataManager.Instance.position / 2 - 4)]
        polygonCollider2D.sensor = true
        const shadow = createUINode("shadow")
        shadow.setParent(node)
        this.shadow = shadow
        const shadowSprite = shadow.addComponent(Sprite)
        shadowSprite.spriteFrame = getFrameAsset(DataManager.Instance.mapAssets, 'shadow.png').spriteFrame// DataManager.Instance.mapAssets.find(item => item.name == 'shadow')
        shadowSprite.color = new math.Color("#ffffff90")
        const shadowTransform = shadow.addComponent(UITransform)
        shadowTransform.setContentSize(DataManager.Instance.width, DataManager.Instance.position)
        const userNode = createUINode('userNode')
        userNode.setParent(node)
        userNode.setPosition(this.positionX, this.positionY)
        const playManager = userNode.addComponent(NpcPlayManager)
        playManager.init(list, DIRECTION_ENUM.TOP, PARAME_NAME_ENUM.IDLE)
        userNode.setScale(2.5, 2.5)
        this.playManager = playManager
        this.userNode = userNode
        setTimeout(res => {
            this.initialize = true
        }, 300)
    }
    // 播放死亡时的动画
    playDizzyTween(keyCode) {
        let shadow_time = .25
        let user_time = .35
        let jump_y = 130
        if (keyCode == 'left' || keyCode == 'right') {
            shadow_time = .3
            user_time = .45
            jump_y = 130
        }
        // 播放阴影变小动画
        tween(this.shadow)
            .to(shadow_time, { scale: new Vec3(.9, .9, 1) })
            .call(() => {
                tween(this.shadow)
                    .to(shadow_time, { scale: new Vec3(1, 1, 1) })
                    .call(() => {
                        this.callback = setTimeout(() => {
                            this.playManager.state = this.static_enum.IDLE
                            this.dizzy = false
                            this.callback_A = setTimeout(() => {
                                this.physicsTestAABB()
                            }, getRandomNumber(300, 600))
                        }, getRandomNumber(4000, 5000))
                    })
                    .start()
            })
            .start()
        // 播放角色位移动画
        tween(this.userNode)
            .to(user_time, { position: new Vec3(this.positionX, this.positionY + jump_y, 0) })
            .call(() => {
                tween(this.userNode)
                    .to(user_time + .05, { position: new Vec3(this.positionX, this.positionY, 0) })
                    .start()
            })
            .start()
    }
    getEmptyPhysicsArr() {
        if(!this.perpetrator) return ['center']
        let { topList, leftList, bottomList, rightList } = this.getPhysicsAABB(['enemy', 'sensor', 'children_lurker', 'slide'])
        let list = [
            {
                type: "top",
                list: topList.filter(item => item.collider.node.uuid != this.perpetrator.uuid)
            },
            {
                type: "left",
                list: leftList.filter(item => item.collider.node.uuid != this.perpetrator.uuid)
            },
            {
                type: "bottom",
                list: bottomList.filter(item => item.collider.node.uuid != this.perpetrator.uuid)
            },
            {
                type: "right",
                list: rightList.filter(item => item.collider.node.uuid != this.perpetrator.uuid)
            }
        ]
        this.status = ""
        let arr = []
        arr = list.filter(item => item.list.length == 0)
        return arr
    }
    // 获取空余的地方
    getEmptyPhysics(direction) {
        let arr = this.getEmptyPhysicsArr()
        let keyCode = ""
        if (arr.length == 0) {
            // 直接死亡
            return
        }
        if(arr.length==1&&arr[0]=='center'){
             keyCode = "center"
        }else{
            if (direction == "top") {
                if (arr.find(item => item.type == 'bottom')) {
                    keyCode = "center"
                }
            } else if (direction == "bottom") {
                if (arr.find(item => item.type == 'top')) {
                    keyCode = "center"
                }
            } else if (direction == "left") {
                if (arr.find(item => item.type == 'right')) {
                    keyCode = "center"
                }
            } else if (direction == "right") {
                if (arr.find(item => item.type == 'left')) {
                    keyCode = "center"
                }
            }
        }
        // 优先原地不动,如果和道具重合，就向道具来的方向停下,如果道具来的方向有道具,就去空白的地方
        if (keyCode == 'center') {
            keyCode = ""
        } else {
            // 优先向道具来的方向去
            if (arr.find(item => item.type == direction)) {
                keyCode = direction
            } else {
                keyCode = arr[getRandomNumber(0, arr.length - 1)]?.type
            }
        }
        if (keyCode == 'top') {
            this.playManager.state = LEAPING_NAME_ENUM.TOPDIZZY
        } else if (keyCode == "left") {
            this.playManager.state = LEAPING_NAME_ENUM.LEFTDIZZY
        } else if (keyCode == "right") {
            this.playManager.state = LEAPING_NAME_ENUM.RIGHTDIZZY
        } else {
            this.playManager.state = LEAPING_NAME_ENUM.BOTTOMDIZZY
        }
        if (keyCode) {
            // 获取走之前的坐标
            this.setStatus(keyCode)
            this.playDizzyTween(keyCode)
            this.walkingStartLogic(keyCode)
        } else {
            // 原地跳跃
            keyCode = "bottom"
            this.setStatus(keyCode)
            this.playDizzyTween(keyCode)
            this.walkingStartLogic("")
        }
    }
    // 获取目标行走开始时的坐标
    walkingStartLogic(keyCode) {

        let { targetX } = this.walkingLogic(keyCode)
        let { x, y } = this.node.getPosition()
        let { width, position } = DataManager.Instance
        let powerY = roundToNearestInteger(y / position)
        let powerX = roundToNearestInteger(x / width)
        let tempX = powerX * width
        this.playManager.targetX = tempX
        if (keyCode == 'left' || keyCode == 'right') {
            this.playManager.targetX = targetX
        } else if (keyCode == 'top' || keyCode == 'bottom') {
            powerY = keyCode == 'bottom' ? powerY - 1 : powerY + 1
            this.playManager.targetX = tempX
        } else {
            this.playManager.targetX = tempX
        }
        let tempY = powerY * position
        this.playManager.targetY = tempY - 30
    }
    dizzy_update() {
        let dizzy_speed = 5
        let { x, y } = this.node.getPosition()
        let { targetX, targetY } = this.playManager
        let rb = this.node.getComponent(RigidBody2D)
        let lv = rb!.linearVelocity;
        y = Math.round(y / dizzy_speed) * dizzy_speed
        x = Math.round(x / dizzy_speed) * dizzy_speed
        targetX = Math.round(targetX / dizzy_speed) * dizzy_speed
        targetY = Math.round(targetY / dizzy_speed) * dizzy_speed
        if (targetX != 0) {
            if (x > parseInt(targetX + '')) {
                lv.x = -dizzy_speed;
                lv = new Vec2(lv.x, 0);
                this.playManager.disabled = true
            } else if (x < parseInt(targetX + '')) {
                lv.x = +dizzy_speed;
                lv = new Vec2(lv.x, 0);
                this.playManager.disabled = true
            } else {
                this.node.setPosition(targetX, y)
                this.playManager.targetX = 0
                this.playManager.disabled = false
            }
        }
        if (targetY != 0) {
            if (y < parseInt(targetY + '')) {
                lv.y = +dizzy_speed;
                lv = new Vec2(0, lv.y);
                this.playManager.disabled = true
            } else if (y > parseInt(targetY + '')) {
                lv.y = -dizzy_speed;
                lv = new Vec2(0, lv.y);
                this.playManager.disabled = true
            } else {
                this.node.setPosition(x, targetY)
                this.playManager.targetY = 0

            }
        }
        if (targetX == 0 && targetY == 0) {
            this.playManager.disabled = false
            this.status = ""
            lv = new Vec2(0, 0);
        }
        rb!.linearVelocity = lv;
    }
    // 修改status
    setStatus(value) {
        if (this.playManager.disabled) {
            return
        }
        switch (value) {
            case "top":
                this.playManager.direction = DIRECTION_ENUM.TOP
                if (!this.dizzy) {
                    this.playManager.state = this.static_enum.TOP
                }
                break;
            case "left":
                this.playManager.direction = DIRECTION_ENUM.LEFT
                if (!this.dizzy) {
                    this.playManager.state = this.static_enum.LEFT
                }
                break;
            case "bottom":
                this.playManager.direction = DIRECTION_ENUM.BOTTOM
                if (!this.dizzy) {
                    this.playManager.state = this.static_enum.BOTTOM
                }
                break;
            case "right":
                this.playManager.direction = DIRECTION_ENUM.RIGHT
                if (!this.dizzy) {
                    this.playManager.state = this.static_enum.RIGHT
                }
                break;
            case "":
                this.status = ""
                break;
        }
        this.status = value
    }
    // 获取上下左右得障碍物信息
    getPhysicsAABB(filterName = ['enemy', 'sensor', 'children_lurker', 'slide', 'role']) {
        let start = new Vec2(this.node.getWorldPosition().x, this.node.getWorldPosition().y)
        let endX = this.node.getWorldPosition().x
        let endY = this.node.getWorldPosition().y
        let topList = []
        let leftList = []
        let bottomList = []
        let rightList = []
        const top = PhysicsSystem2D.instance.raycast(start, new Vec2(endX, endY + 120), ERaycast2DType.All);
        topList = top.filter((item => !filterName.find(item1 => item.collider.node.name.includes(item1))))
        const bottom = PhysicsSystem2D.instance.raycast(start, new Vec2(endX, endY - 120), ERaycast2DType.All);
        bottomList = bottom.filter((item => !filterName.find(item1 => item.collider.node.name.includes(item1))))
        const left = PhysicsSystem2D.instance.raycast(start, new Vec2(endX - 120, endY), ERaycast2DType.All);
        leftList = left.filter((item => !filterName.find(item1 => item.collider.node.name.includes(item1))))
        const right = PhysicsSystem2D.instance.raycast(start, new Vec2(endX + 120, endY), ERaycast2DType.All)
        rightList = right.filter((item => !filterName.find(item1 => item.collider.node.name.includes(item1))))
        return { topList, leftList, bottomList, rightList }
    }
    // 判断上下左右是否有障碍物，
    physicsTestAABB() {
        if (this.status != '' || this.dizzy) return
        let { topList, leftList, bottomList, rightList } = this.getPhysicsAABB()
        let runList = []
        let { direction } = this.playManager
        // 代表上面是空的,可以行走
        if (topList.length == 0) {
            runList.push("top")
        }
        if (bottomList.length == 0) {
            runList.push("bottom")
        }
        if (leftList.length == 0) {
            runList.push("left")
        }
        if (rightList.length == 0) {
            runList.push("right")
        }
        let keyCode = ""
        // 三、四个方向的话,如果包含当前方向，优先当前方向
        if (runList.length >= 3) {
            if (direction == DIRECTION_ENUM.TOP && runList.find(item => item == "top")) {
                for (let i = 0; i < 10; i++) {
                    runList.push("top")
                }
            } else if (direction == DIRECTION_ENUM.BOTTOM && runList.find(item => item == "bottom")) {
                for (let i = 0; i < 10; i++) {
                    runList.push("bottom")
                }
            } else if (direction == DIRECTION_ENUM.LEFT && runList.find(item => item == "left")) {
                for (let i = 0; i < 10; i++) {
                    runList.push("left")
                }
            } else if (direction == DIRECTION_ENUM.RIGHT && runList.find(item => item == "right")) {
                for (let i = 0; i < 10; i++) {
                    runList.push("right")
                }
            }
            keyCode = runList[getRandomNumber(0, runList.length - 1)]
        } else if (runList.length == 2) {
            // 两个方向的话 优先走当前方向和对向方向
            // 如果是上、左/右
            if (direction == DIRECTION_ENUM.TOP && runList.find(item => item == "top")) {
                for (let i = 0; i < 10; i++) {
                    runList.push("top")
                }
            } else if (direction == DIRECTION_ENUM.BOTTOM && runList.find(item => item == "bottom")) {
                // 如果是下、左/右
                for (let i = 0; i < 10; i++) {
                    runList.push("bottom")
                }
            } else if (direction == DIRECTION_ENUM.LEFT && runList.find(item => item == "left")) {
                // 左、上/下
                for (let i = 0; i < 10; i++) {
                    runList.push("left")
                }
            } else if (direction == DIRECTION_ENUM.RIGHT && runList.find(item => item == "right")) {
                // 右、上/下
                for (let i = 0; i < 10; i++) {
                    runList.push("right")
                }
            }
            keyCode = runList[getRandomNumber(0, runList.length - 1)]
        } else if (runList.length == 1) {
            // 一个方向的话
            keyCode = runList[0]
        }
        this.setStatus(keyCode)
        let { targetX, targetY } = this.walkingLogic(keyCode)
        if (this.nodeName == 'LeapingEnemy') {
            let line_direction = DIRECTION_ENUM.TOP
            if (keyCode == 'left') {
                line_direction = DIRECTION_ENUM.LEFT
            } else if (keyCode == 'right') {
                line_direction = DIRECTION_ENUM.RIGHT
            } else if (keyCode == 'bottom') {
                line_direction = DIRECTION_ENUM.BOTTOM
            }
            this.lineList = [{
                targetX,
                targetY,
                status: keyCode,
                direction: line_direction
            }]
        } else {
            this.playManager.targetX = targetX
            this.playManager.targetY = targetY
        }
    }
    // 获取目标行走结束的坐标
    walkingLogic(keyCode) {
        let { width, position, mapWidth, mapHeight, height } = DataManager.Instance
        let { targetX, targetY, end_w, end_a, end_s, end_d } = this.playManager
        let { x, y } = this.node.getPosition()
        let tempX = targetX == 0 ? parseInt(x + width + '') : targetX
        let tempY = targetY == 0 ? parseInt(y + '') : targetY
        let powerX, powerY
        switch (keyCode) {
            case "top":
                powerY = Math.floor(y / position)
                tempY = position * powerY + position + ((height - position))
                let endW = end_w == 0 ? -(position + ((height - position) / 2)) : end_w
                if (tempY > endW) {
                    tempY = endW
                }
                // 怪物冲刺需要单独处理
                if (this.nodeName == 'ChargingEnemy') {
                    if (end_w != 0) {
                        tempY = end_w
                    }
                }
                break;
            case "bottom":
                powerY = Math.floor(y / position)
                tempY = position * powerY - (height - position) + ((height - position) / 2)
                let endS = end_s == 0 ? -(mapHeight - height) : end_s
                if (tempY <= endS) {
                    tempY = endS
                }
                // 怪物冲刺需要单独处理
                if (this.nodeName == 'ChargingEnemy') {
                    if (end_s != 0) {
                        tempY = end_s
                    }
                }
                break;
            case "left":
                powerX = Math.round(x / width)
                // 小于最小宽度的话，就不赋值
                let endA = end_a == 0 ? width * powerX - width : end_a
                if (width <= endA) {
                    tempX = endA
                }
                // if(tempX)   
                break;
            case "right":
                // 向上取整
                powerX = Math.floor(x / width) //取当前移动的格子数
                // end_d 预设的目标点  
                // width * powerX 当前格子的极限距离 +150 是因为右侧没有障碍物，要往右走
                let endD = end_d == 0 ? width * powerX + width : end_d
                // 超过最大宽度的话，就不赋值
                if (mapWidth >= endD) {
                    tempX = endD
                }
                break;
        }
        return { targetX: Math.round(tempX / this.speed) * this.speed, targetY: Math.round(tempY / this.speed) * this.speed }
    }
    // 比较两个坐标哪个离目标坐标更近
    coordinateComparison(list) {
        let target = new Vec2(this.node.getWorldPosition().x, this.node.getWorldPosition().y)
        let nodeList = []
        list.forEach(item => {
            let point = item.point
            nodeList.push({
                ...item,
                number: Math.sqrt(Math.pow(point.x - target.x, 2) + Math.pow(point.y - target.y, 2))
            })
        })
        let min = nodeList.sort((a, b) => {
            return a.number - b.number
        })
        return min
    }
}


